from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from apps.ai.services.ocr_service import OCRService, OCRServiceError
from ..services.note_ocr_service import OCRService as NoteOCRService
from ..services.table_ocr_service import TableOCRService, OCRServiceError as TableOCRServiceError
from .global_responses import BaseResponse
import logging
from django.core.cache import cache
import hashlib
import datetime

logger = logging.getLogger('apps')

@method_decorator(csrf_exempt, name='dispatch')
class OCRRecognitionView(APIView):
    """OCR文字识别视图"""
    permission_classes = [IsAuthenticated]
    
    def post(self, request):
        try:
            # 获取识别选项
            options = {}
            if 'character' in request.data:
                options['character'] = int(request.data.get('character', 0))
            if 'straighten' in request.data:
                options['straighten'] = int(request.data.get('straighten', 0))
            
            # 检查是否提供了图片URL
            image_url = request.data.get('image_url')
            if image_url:
                return self._process_image_url(request, image_url, options)
            
            # 获取图片文件
            image_file = request.FILES.get('image')
            if not image_file:
                return BaseResponse.error('未接收到图片文件或URL')
            
            return self._process_image_file(request, image_file, options)
            
        except OCRServiceError as e:
            logger.error(f"OCR服务错误: {str(e)}")
            return BaseResponse.error(str(e), status=e.http_status)
            
        except Exception as e:
            logger.error(
                "OCR识别失败: 错误=%s",
                str(e),
                exc_info=True
            )
            
            return BaseResponse.error(f'OCR识别失败: {str(e)}', status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    def _process_image_file(self, request, image_file, options):
        """处理图片文件"""
        # 记录图片信息
        user_id = request.user.pk if request.user.is_authenticated else 'anonymous'
        logger.info(
            "接收到图片文件: 用户=%s, 文件名=%s, 大小=%d字节",
            user_id,
            image_file.name,
            image_file.size
        )
        
        # 生成缓存键
        cache_key = f"ocr_result_{user_id}_{image_file.name}_{image_file.size}"
        
        # 尝试从缓存获取结果
        cached_result = cache.get(cache_key)
        if cached_result:
            logger.info(f"从缓存获取OCR结果: {cache_key}")
            return BaseResponse.success({
                'text': cached_result,
                'from_cache': True
            })
        
        # 初始化OCR服务
        ocr_service = OCRService()
        
        # 验证图片
        if not ocr_service.validate_image(image_file):
            logger.warning("无效图片文件，用户=%s，文件名=%s，大小=%s", 
                         user_id, image_file.name, image_file.size)
            return BaseResponse.error('请上传有效的图片文件(jpg/jpeg/png/bmp/pdf)，且大小不超过10MB')
        
        # 执行OCR识别
        recognized_text = ocr_service.recognize_text(image_file, options)
        
        # 缓存结果
        cache.set(cache_key, recognized_text, 3600)  # 缓存1小时
        
        return BaseResponse.success({
            'text': recognized_text,
            'from_cache': False
        })
    
    def _process_image_url(self, request, image_url, options):
        """处理图片URL"""
        # 记录URL信息
        user_id = request.user.pk if request.user.is_authenticated else 'anonymous'
        logger.info(
            "接收到图片URL: 用户=%s, URL=%s",
            user_id,
            image_url
        )
        
        # 生成缓存键
        cache_key = f"ocr_url_result_{user_id}_{hash(image_url)}"
        
        # 尝试从缓存获取结果
        cached_result = cache.get(cache_key)
        if cached_result:
            logger.info(f"从缓存获取OCR结果: {cache_key}")
            return BaseResponse.success({
                'text': cached_result,
                'from_cache': True
            })
        
        # 初始化OCR服务
        ocr_service = OCRService()
        
        # 执行OCR识别
        recognized_text = ocr_service.recognize_text_from_url(image_url, options)
        
        # 缓存结果
        cache.set(cache_key, recognized_text, 3600)  # 缓存1小时
        
        return BaseResponse.success({
            'text': recognized_text,
            'from_cache': False
        })


class NoteOCRRecognitionView(APIView):
    """
    提供PDF识别服务，将PDF文件转换为Markdown格式
    """
    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)
    
    def post(self, request):
        """
        将PDF转换为Markdown
        
        请求方式1（文件上传）:
        Content-Type: multipart/form-data
        - pdf_file: PDF文件
        
        请求方式2（URL）:
        Content-Type: application/json
        {
            "pdf_url": "PDF文件的URL"
        }
        
        返回:
        {
            "status": "success",
            "message": "操作成功",
            "data": {
                "markdown": "转换后的Markdown文本",
                "from_cache": false
            }
        }
        """
        try:
            # 初始化OCR服务
            ocr_service = NoteOCRService()
            
            # 检查请求类型（文件上传或URL）
            if request.FILES and 'pdf_file' in request.FILES:
                # 处理文件上传
                pdf_file = request.FILES['pdf_file']
                
                # 检查文件有效性
                if not ocr_service.validate_pdf(pdf_file):
                    return BaseResponse.error('无效的文件类型，仅支持PDF文件和图片文件')
                
                # 计算文件内容哈希，用于缓存
                file_hash = self._compute_file_hash(pdf_file)
                cache_key = f"ocr_result:{file_hash}"
                
                # 检查缓存
                cached_result = cache.get(cache_key)
                if cached_result:
                    logger.info(f"从缓存返回OCR结果，文件哈希: {file_hash[:10]}...")
                    return BaseResponse.success({
                        'markdown': cached_result,
                        'from_cache': True
                    })
                
                # 执行OCR
                result = ocr_service.recognize_text(pdf_file)
                
                # 缓存结果（24小时有效）
                cache.set(cache_key, result, 60 * 60 * 24)
                
                return BaseResponse.success({
                    'markdown': result,
                    'from_cache': False
                })
            
            elif request.data and 'pdf_url' in request.data:
                # 处理URL请求
                pdf_url = request.data.get('pdf_url')
                if not pdf_url:
                    return BaseResponse.error('PDF URL不能为空')
                
                # 计算URL哈希，用于缓存
                url_hash = hashlib.md5(pdf_url.encode()).hexdigest()
                cache_key = f"ocr_url_result:{url_hash}"
                
                # 检查缓存
                cached_result = cache.get(cache_key)
                if cached_result:
                    logger.info(f"从缓存返回OCR结果，URL哈希: {url_hash[:10]}...")
                    return BaseResponse.success({
                        'markdown': cached_result,
                        'from_cache': True
                    })
                
                # 执行OCR
                result = ocr_service.recognize_text_from_url(pdf_url)
                
                # 缓存结果（24小时有效）
                cache.set(cache_key, result, 60 * 60 * 24)
                
                return BaseResponse.success({
                    'markdown': result,
                    'from_cache': False
                })
            else:
                return BaseResponse.error('请提供PDF文件或PDF URL')
                
        except Exception as e:
            logger.error(f"OCR处理失败: {str(e)}", exc_info=True)
            return BaseResponse.error(f'处理失败: {str(e)}', status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    def _compute_file_hash(self, file):
        """计算文件的MD5哈希值"""
        md5 = hashlib.md5()
        for chunk in file.chunks():
            md5.update(chunk)
        file.seek(0)  # 重置文件指针
        return md5.hexdigest()

@method_decorator(csrf_exempt, name='dispatch')
class TableRecognitionView(APIView):
    """表格识别视图"""
    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)
    
    def post(self, request):
        """
        识别图片中的表格并转换为Markdown格式
        
        请求方式1（文件上传）:
        Content-Type: multipart/form-data
        - image: 图片文件
        
        请求方式2（URL）:
        Content-Type: application/json
        {
            "image_url": "图片文件的URL"
        }
        
        可选参数:
        - character: 是否返回完整的字符信息，0或1，默认0
        - straighten: 坐标系选项，0或1，默认0
        - output_order: 输出格式，可选值: perpendicular, table_and_remain, table_only
        - table_type_hint: 表格类型提示，可选值: automatic, table_with_line, table_with_few_line, table_without_line
        - excel: 是否输出excel文件，0或1，默认0
        
        返回:
        {
            "status": "success",
            "message": "操作成功",
            "data": {
                "markdown": "表格的Markdown文本",
                "excel": "Base64编码的Excel文件（如果excel=1）",
                "raw_result": "完整的识别结果",
                "from_cache": false
            }
        }
        """
        try:
            # 获取识别选项
            options = {}
            
            # 处理可选参数
            if 'character' in request.data:
                options['character'] = int(request.data.get('character', 0))
            if 'straighten' in request.data:
                options['straighten'] = int(request.data.get('straighten', 0))
            if 'output_order' in request.data and request.data['output_order'] in ['perpendicular', 'table_and_remain', 'table_only']:
                options['output_order'] = request.data['output_order']
            if 'table_type_hint' in request.data and request.data['table_type_hint'] in ['automatic', 'table_with_line', 'table_with_few_line', 'table_without_line']:
                options['table_type_hint'] = request.data['table_type_hint']
            if 'excel' in request.data:
                options['excel'] = int(request.data.get('excel', 0))
            
            # 检查是否提供了图片URL
            image_url = request.data.get('image_url')
            if image_url:
                return self._process_image_url(request, image_url, options)
            
            # 获取图片文件
            image_file = request.FILES.get('image')
            if not image_file:
                return BaseResponse.error('未接收到图片文件或URL')
            
            return self._process_image_file(request, image_file, options)
            
        except TableOCRServiceError as e:
            logger.error(f"表格识别服务错误: {str(e)}")
            return BaseResponse.error(str(e), status=e.http_status)
            
        except Exception as e:
            logger.error(
                "表格识别失败: 错误=%s",
                str(e),
                exc_info=True
            )
            
            return BaseResponse.error(f'表格识别失败: {str(e)}', status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    def _process_image_file(self, request, image_file, options):
        """处理图片文件"""
        # 记录图片信息
        user_id = request.user.pk if request.user.is_authenticated else 'anonymous'
        logger.info(
            "接收到表格图片文件: 用户=%s, 文件名=%s, 大小=%d字节",
            user_id,
            image_file.name,
            image_file.size
        )
        
        # 生成缓存键
        options_str = ''.join([f"{k}={v}" for k, v in sorted(options.items())])
        cache_key = f"table_ocr_result_{user_id}_{image_file.name}_{image_file.size}_{options_str}"
        
        # 判断是否强制刷新缓存（用于调试）
        force_refresh = request.query_params.get('force_refresh', '').lower() == 'true'
        
        # 尝试从缓存获取结果
        cached_result = None if force_refresh else cache.get(cache_key)
        if cached_result:
            logger.info(f"从缓存获取表格识别结果: {cache_key}")
            return BaseResponse.success(cached_result)
        
        # 初始化表格OCR服务
        table_ocr_service = TableOCRService()
        
        # 验证图片
        if not table_ocr_service.validate_image(image_file):
            logger.warning("无效图片文件，用户=%s，文件名=%s，大小=%s", 
                         user_id, image_file.name, image_file.size)
            return BaseResponse.error('请上传有效的图片文件(jpg/jpeg/png/bmp/pdf/tiff/gif)，且大小不超过10MB')
        
        # 执行表格识别
        result = table_ocr_service.recognize_table(image_file, options)
        logger.info(f"表格识别原始结果结构: {str(result.keys()) if isinstance(result, dict) else type(result)}")
        
        # 提取Markdown
        markdown_text = table_ocr_service.extract_tables_to_markdown(result)
        logger.info(f"表格转Markdown结果长度: {len(markdown_text)}")
        
        # 处理响应数据
        response_data = {
            'markdown': markdown_text,
            'from_cache': False
        }
        
        # 如果请求了Excel数据
        if options.get('excel', 0) == 1:
            response_data['excel'] = table_ocr_service.process_excel_data(result)
        
        # 根据请求参数决定是否返回原始结果
        include_raw = request.query_params.get('include_raw_result', '').lower() == 'true'
        if include_raw:
            # 为了JSON序列化，不直接返回可能包含非序列化内容的原始结果
            try:
                import json
                # 尝试将结果转换为JSON字符串然后再解析回来，确保可序列化
                raw_json = json.dumps(result)
                response_data['raw_result'] = json.loads(raw_json)
                logger.info("成功包含原始结果在响应中")
            except Exception as e:
                logger.error(f"序列化原始结果失败: {str(e)}")
                response_data['raw_result_error'] = f"无法序列化原始结果: {str(e)}"
        
        # 添加响应元数据，便于调试
        response_data['metadata'] = {
            'recognized_at': str(datetime.datetime.now()),
            'options_used': options,
        }
        
        # 缓存结果
        cache.set(cache_key, response_data, 3600)  # 缓存1小时
        
        return BaseResponse.success(response_data)
    
    def _process_image_url(self, request, image_url, options):
        """处理图片URL"""
        # 记录URL信息
        user_id = request.user.pk if request.user.is_authenticated else 'anonymous'
        logger.info(
            "接收到表格图片URL: 用户=%s, URL=%s",
            user_id,
            image_url
        )
        
        # 生成缓存键
        options_str = ''.join([f"{k}={v}" for k, v in sorted(options.items())])
        url_hash = hashlib.md5(image_url.encode()).hexdigest()
        cache_key = f"table_ocr_url_result_{user_id}_{url_hash}_{options_str}"
        
        # 判断是否强制刷新缓存（用于调试）
        force_refresh = request.query_params.get('force_refresh', '').lower() == 'true'
        
        # 尝试从缓存获取结果
        cached_result = None if force_refresh else cache.get(cache_key)
        if cached_result:
            logger.info(f"从缓存获取表格识别结果: {cache_key}")
            return BaseResponse.success(cached_result)
        
        # 初始化表格OCR服务
        table_ocr_service = TableOCRService()
        
        # 执行表格识别
        result = table_ocr_service.recognize_table_from_url(image_url, options)
        logger.info(f"URL表格识别原始结果结构: {str(result.keys()) if isinstance(result, dict) else type(result)}")
        
        # 提取Markdown
        markdown_text = table_ocr_service.extract_tables_to_markdown(result)
        logger.info(f"URL表格转Markdown结果长度: {len(markdown_text)}")
        
        # 处理响应数据
        response_data = {
            'markdown': markdown_text,
            'from_cache': False
        }
        
        # 如果请求了Excel数据
        if options.get('excel', 0) == 1:
            response_data['excel'] = table_ocr_service.process_excel_data(result)
        
        # 根据请求参数决定是否返回原始结果
        include_raw = request.query_params.get('include_raw_result', '').lower() == 'true'
        if include_raw:
            # 为了JSON序列化，不直接返回可能包含非序列化内容的原始结果
            try:
                import json
                # 尝试将结果转换为JSON字符串然后再解析回来，确保可序列化
                raw_json = json.dumps(result)
                response_data['raw_result'] = json.loads(raw_json)
                logger.info("成功包含URL原始结果在响应中")
            except Exception as e:
                logger.error(f"序列化URL原始结果失败: {str(e)}")
                response_data['raw_result_error'] = f"无法序列化原始结果: {str(e)}"
        
        # 添加响应元数据，便于调试
        response_data['metadata'] = {
            'recognized_at': str(datetime.datetime.now()),
            'options_used': options,
            'image_url_hash': url_hash[:10] # 仅包含URL哈希的前10位，避免泄露完整URL
        }
        
        # 缓存结果
        cache.set(cache_key, response_data, 3600)  # 缓存1小时
        
        return BaseResponse.success(response_data)
